In this workbook we construct the non-hierarchical P/NBD models on the synthetic data with the longer timeframe.
Load Short-Timeframe Synthetic Transaction Data
We now want to load the CD-NOW transaction data.
Code
customer_cohortdata_tbl <- read_rds ("data/shortsynth_customer_cohort_data_tbl.rds" )
customer_cohortdata_tbl |> glimpse ()
Rows: 5,000
Columns: 5
$ customer_id <chr> "SFC202001_0001", "SFC202001_0002", "SFC202001_0003", …
$ cohort_qtr <chr> "2020 Q1", "2020 Q1", "2020 Q1", "2020 Q1", "2020 Q1",…
$ cohort_ym <chr> "2020 01", "2020 01", "2020 01", "2020 01", "2020 01",…
$ first_tnx_date <dttm> 2020-01-01 02:15:58, 2020-01-01 00:40:17, 2020-01-01 …
$ total_tnx_count <int> 3, 9, 1, 2, 5, 1, 4, 6, 2, 4, 1, 11, 3, 3, 1, 1, 11, 3…
Code
customer_transactions_tbl <- read_rds ("data/shortsynth_transaction_data_tbl.rds" )
customer_transactions_tbl |> glimpse ()
Rows: 29,454
Columns: 7
$ customer_id <chr> "SFC202001_0002", "SFC202001_0001", "SFC202001_0004", "S…
$ tnx_timestamp <dttm> 2020-01-01 00:40:17, 2020-01-01 02:15:58, 2020-01-01 18…
$ tnx_dow <fct> Wed, Wed, Wed, Wed, Thu, Thu, Thu, Thu, Thu, Thu, Thu, F…
$ tnx_month <fct> Jan, Jan, Jan, Jan, Jan, Jan, Jan, Jan, Jan, Jan, Jan, J…
$ tnx_week <chr> "00", "00", "00", "00", "00", "00", "00", "00", "00", "0…
$ invoice_id <chr> "T20200101-0001", "T20200101-0002", "T20200101-0003", "T…
$ tnx_amount <dbl> 51.73, 139.05, 11.72, 88.30, 1.16, 0.95, 127.85, 35.07, …
Code
customer_subset_id <- read_rds ("data/shortsynth_customer_subset_ids.rds" )
customer_subset_id |> glimpse ()
Factor w/ 5000 levels "SFC202001_0002",..: 2 3 8 10 14 16 17 21 25 27 ...
We re-produce the visualisation of the transaction times we used in previous workbooks.
Code
plot_tbl <- customer_transactions_tbl |>
group_nest (customer_id, .key = "cust_data" ) |>
filter (map_int (cust_data, nrow) > 3 ) |>
slice_sample (n = 30 ) |>
unnest (cust_data)
ggplot (plot_tbl, aes (x = tnx_timestamp, y = customer_id)) +
geom_line () +
geom_point () +
labs (
x = "Date" ,
y = "Customer ID" ,
title = "Visualisation of Customer Transaction Times"
) +
theme (axis.text.y = element_text (size = 10 ))
Load Derived Data
Code
obs_fitdata_tbl <- read_rds ("data/shortsynth_obs_fitdata_tbl.rds" )
obs_validdata_tbl <- read_rds ("data/shortsynth_obs_validdata_tbl.rds" )
customer_fit_stats_tbl <- obs_fitdata_tbl |>
rename (x = tnx_count)
Load Subset Data
We also want to construct our data subsets for the purposes of speeding up our valuations.
Code
customer_fit_subset_tbl <- obs_fitdata_tbl |>
filter (customer_id %in% customer_subset_id)
customer_fit_subset_tbl |> glimpse ()
Rows: 1,000
Columns: 6
$ customer_id <fct> SFC202001_0001, SFC202001_0004, SFC202001_0008, SFC2020…
$ first_tnx_date <dttm> 2020-01-01 02:15:58, 2020-01-01 18:04:32, 2020-01-02 1…
$ last_tnx_date <dttm> 2020-02-20 14:43:57, 2020-01-10 17:49:12, 2020-07-17 0…
$ tnx_count <dbl> 2, 1, 5, 4, 0, 10, 10, 0, 0, 0, 6, 2, 0, 0, 0, 1, 0, 3,…
$ t_x <dbl> 7.2170614, 1.2841927, 28.0650995, 12.3070761, 0.0000000…
$ T_cal <dbl> 104.4151, 104.3210, 104.1918, 104.1751, 104.0693, 104.0…
Code
customer_valid_subset_tbl <- obs_validdata_tbl |>
filter (customer_id %in% customer_subset_id)
customer_valid_subset_tbl |> glimpse ()
Rows: 1,000
Columns: 3
$ customer_id <fct> SFC202001_0001, SFC202001_0004, SFC202001_0008, SFC2…
$ tnx_count <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ tnx_last_interval <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
We now use these datasets to set the start and end dates for our various validation methods.
Code
dates_lst <- read_rds ("data/shortsynth_simulation_dates.rds" )
use_fit_start_date <- dates_lst$ use_fit_start_date
use_fit_end_date <- dates_lst$ use_fit_end_date
use_valid_start_date <- dates_lst$ use_valid_start_date
use_valid_end_date <- dates_lst$ use_valid_end_date
Before we start on that, we set a few parameters for the workbook to organise our Stan code.
Code
stan_modeldir <- "stan_models"
stan_codedir <- "stan_code"
Fit First Hierarchical Lambda Model
Our first hierarchical model puts a hierarchical prior around the mean of our population \(\lambda\) - lambda_mn.
Once again we use a Gamma prior for it.
Compile and Fit Stan Model
We now compile this model using CmdStanR.
Code
pnbd_onehierlambda_stanmodel <- cmdstan_model (
"stan_code/pnbd_onehier_lambda.stan" ,
include_paths = stan_codedir,
pedantic = TRUE ,
dir = stan_modeldir
)
We then use this compiled model with our data to produce a fit of the data.
Code
stan_modelname <- "pnbd_short_onehierlambda1"
stanfit_prefix <- str_c ("fit_" , stan_modelname)
stanfit_seed <- stanfit_seed + 1
stanfit_object_file <- glue ("data/{stanfit_prefix}_stanfit.rds" )
stan_data_lst <- customer_fit_stats_tbl |>
select (customer_id, x, t_x, T_cal) |>
compose_data (
hier_lambda_mn_p1 = 0.25 ,
hier_lambda_mn_p2 = 1 ,
lambda_cv = 1.00 ,
mu_mn = 0.10 ,
mu_cv = 1.00 ,
)
if (! file_exists (stanfit_object_file)) {
pnbd_short_onehierlambda1_stanfit <- pnbd_onehierlambda_stanmodel$ sample (
data = stan_data_lst,
chains = 4 ,
iter_warmup = 500 ,
iter_sampling = 500 ,
seed = stanfit_seed,
save_warmup = TRUE ,
output_dir = stan_modeldir,
output_basename = stanfit_prefix,
)
pnbd_short_onehierlambda1_stanfit$ save_object (stanfit_object_file, compress = "gzip" )
} else {
pnbd_short_onehierlambda1_stanfit <- read_rds (stanfit_object_file)
}
pnbd_short_onehierlambda1_stanfit$ summary ()
# A tibble: 9,963 × 10
variable mean median sd mad q5 q95 rhat ess_bulk
<chr> <num> <num> <num> <num> <num> <num> <num> <num>
1 lp__ -4.69e+4 -4.69e+4 6.41e+1 6.29e+1 -4.70e+4 -4.68e+4 1.00 546.
2 lambda_mn 2.49e-1 2.49e-1 5.85e-3 5.82e-3 2.39e-1 2.59e-1 1.00 1519.
3 lambda[1] 4.36e-1 4.20e-1 1.47e-1 1.43e-1 2.24e-1 7.05e-1 1.00 2862.
4 lambda[2] 2.08e-1 1.78e-1 1.32e-1 1.16e-1 5.03e-2 4.70e-1 0.999 2869.
5 lambda[3] 2.58e-1 2.09e-1 2.06e-1 1.62e-1 4.02e-2 6.44e-1 1.00 2587.
6 lambda[4] 1.37e-1 8.24e-2 1.63e-1 9.40e-2 4.90e-3 4.42e-1 1.00 1750.
7 lambda[5] 4.86e-1 4.41e-1 2.65e-1 2.40e-1 1.47e-1 9.86e-1 1.00 2470.
8 lambda[6] 2.40e-1 1.90e-1 1.96e-1 1.53e-1 3.21e-2 6.21e-1 1.00 1973.
9 lambda[7] 1.43e-1 8.11e-2 1.73e-1 9.21e-2 5.69e-3 4.92e-1 1.00 2591.
10 lambda[8] 1.62e-1 1.54e-1 7.04e-2 6.59e-2 6.86e-2 2.95e-1 1.00 2095.
# ℹ 9,953 more rows
# ℹ 1 more variable: ess_tail <num>
We have some basic HMC-based validity statistics we can check.
Code
pnbd_short_onehierlambda1_stanfit$ cmdstan_diagnose ()
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda1-1.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda1-2.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda1-3.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda1-4.csv not found
No valid input files, exiting.
Visual Diagnostics of the Sample Validity
Now that we have a sample from the posterior distribution we need to create a few different visualisations of the diagnostics.
Code
parameter_subset <- c (
"lambda_mn" ,
"lambda[1]" , "lambda[2]" , "lambda[3]" , "lambda[4]" ,
"mu[1]" , "mu[2]" , "mu[3]" , "mu[4]"
)
pnbd_short_onehierlambda1_stanfit$ draws (inc_warmup = FALSE ) |>
mcmc_trace (pars = parameter_subset) +
expand_limits (y = 0 ) +
labs (
x = "Iteration" ,
y = "Value" ,
title = "Traceplot of Sample of Lambda and Mu Values"
) +
theme (axis.text.x = element_text (size = 10 ))
We also check \(N_{eff}\) as a quick diagnostic of the fit.
Code
pnbd_short_onehierlambda1_stanfit |>
neff_ratio (pars = c ("lambda" , "mu" )) |>
mcmc_neff () +
ggtitle ("Plot of Parameter Effective Sample Sizes" )
Assess the Model
As we intend to run the same logic to assess each of our models, we have combined all this logic into a single function run_model_assessment, to run the simulations and combine the datasets.
Code
pnbd_stanfit <- pnbd_short_onehierlambda1_stanfit |>
recover_types (customer_fit_stats_tbl)
pnbd_short_onehierlambda1_assess_data_lst <- run_model_assessment (
model_stanfit = pnbd_stanfit,
insample_tbl = customer_fit_subset_tbl,
fit_label = "pnbd_short_onehierlambda1" ,
fit_end_dttm = use_fit_end_date |> as.POSIXct (),
valid_start_dttm = use_valid_start_date |> as.POSIXct (),
valid_end_dttm = use_valid_end_date |> as.POSIXct (),
sim_seed = 4210
)
pnbd_short_onehierlambda1_assess_data_lst |> glimpse ()
List of 5
$ model_fit_index_filepath : 'glue' chr "data/pnbd_short_onehierlambda1_assess_fit_index_tbl.rds"
$ model_valid_index_filepath : 'glue' chr "data/pnbd_short_onehierlambda1_assess_valid_index_tbl.rds"
$ model_simstats_filepath : 'glue' chr "data/pnbd_short_onehierlambda1_assess_model_simstats_tbl.rds"
$ model_fit_simstats_filepath : 'glue' chr "data/pnbd_short_onehierlambda1_assess_fit_simstats_tbl.rds"
$ model_valid_simstats_filepath: 'glue' chr "data/pnbd_short_onehierlambda1_assess_valid_simstats_tbl.rds"
Check In-Sample Data Validation
We first check the model against the in-sample data.
Code
simdata_tbl <- pnbd_short_onehierlambda1_assess_data_lst |>
use_series (model_fit_simstats_filepath) |>
read_rds ()
insample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_fit_subset_tbl,
simdata_tbl = simdata_tbl
)
insample_plots_lst$ multi_plot |> print ()
Code
insample_plots_lst$ total_plot |> print ()
Code
insample_plots_lst$ quant_plot |> print ()
This fit looks reasonable and appears to capture most of the aspects of the data used to fit it. Given that this is a synthetic dataset, this is not surprising, but at least we appreciate that our model is valid.
Check Out-of-Sample Data Validation
We now repeat for the out-of-sample data.
Code
simdata_tbl <- pnbd_short_onehierlambda1_assess_data_lst |>
use_series (model_valid_simstats_filepath) |>
read_rds ()
outsample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_valid_subset_tbl,
simdata_tbl = simdata_tbl
)
outsample_plots_lst$ multi_plot |> print ()
Code
outsample_plots_lst$ total_plot |> print ()
Code
outsample_plots_lst$ quant_plot |> print ()
As for our short time frame data, overall our model is working well.
Fit Second Hierarchical Lambda Model
In this model, we are going with a broadly similar model but we are instead using a different mean for our hierarchical prior.
Fit Stan Model
We now want to fit the model to our data using this alternative prior for lambda_mn.
Code
stan_modelname <- "pnbd_short_onehierlambda2"
stanfit_prefix <- str_c ("fit_" , stan_modelname)
stanfit_seed <- stanfit_seed + 1
stanfit_object_file <- glue ("data/{stanfit_prefix}_stanfit.rds" )
stan_data_lst <- customer_fit_stats_tbl |>
select (customer_id, x, t_x, T_cal) |>
compose_data (
hier_lambda_mn_p1 = 0.50 ,
hier_lambda_mn_p2 = 1 ,
lambda_cv = 1.00 ,
mu_mn = 0.10 ,
mu_cv = 1.00 ,
)
if (! file_exists (stanfit_object_file)) {
pnbd_short_onehierlambda2_stanfit <- pnbd_onehierlambda_stanmodel$ sample (
data = stan_data_lst,
chains = 4 ,
iter_warmup = 500 ,
iter_sampling = 500 ,
seed = stanfit_seed,
save_warmup = TRUE ,
output_dir = stan_modeldir,
output_basename = stanfit_prefix,
)
pnbd_short_onehierlambda2_stanfit$ save_object (stanfit_object_file, compress = "gzip" )
} else {
pnbd_short_onehierlambda2_stanfit <- read_rds (stanfit_object_file)
}
pnbd_short_onehierlambda2_stanfit$ summary ()
# A tibble: 9,963 × 10
variable mean median sd mad q5 q95 rhat ess_bulk
<chr> <num> <num> <num> <num> <num> <num> <num> <num>
1 lp__ -4.69e+4 -4.69e+4 6.25e+1 6.34e+1 -4.70e+4 -4.68e+4 1.01 621.
2 lambda_mn 2.49e-1 2.49e-1 5.73e-3 5.83e-3 2.40e-1 2.58e-1 1.00 1376.
3 lambda[1] 4.39e-1 4.18e-1 1.48e-1 1.52e-1 2.31e-1 7.07e-1 1.00 2541.
4 lambda[2] 2.08e-1 1.78e-1 1.38e-1 1.22e-1 4.66e-2 4.68e-1 1.00 2096.
5 lambda[3] 2.62e-1 2.12e-1 2.02e-1 1.67e-1 3.95e-2 6.66e-1 1.00 1713.
6 lambda[4] 1.42e-1 7.80e-2 1.80e-1 9.11e-2 4.21e-3 4.97e-1 1.00 1891.
7 lambda[5] 4.91e-1 4.38e-1 2.70e-1 2.52e-1 1.44e-1 1.01e+0 1.00 2188.
8 lambda[6] 2.45e-1 1.89e-1 1.99e-1 1.54e-1 3.13e-2 6.42e-1 1.00 2137.
9 lambda[7] 1.40e-1 8.29e-2 1.68e-1 9.21e-2 5.23e-3 4.52e-1 1.00 1787.
10 lambda[8] 1.62e-1 1.55e-1 6.98e-2 6.98e-2 6.76e-2 2.87e-1 1.00 2572.
# ℹ 9,953 more rows
# ℹ 1 more variable: ess_tail <num>
We have some basic HMC-based validity statistics we can check.
Code
pnbd_short_onehierlambda2_stanfit$ cmdstan_diagnose ()
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda2-1.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda2-2.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda2-3.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehierlambda2-4.csv not found
No valid input files, exiting.
Visual Diagnostics of the Sample Validity
Now that we have a sample from the posterior distribution we need to create a few different visualisations of the diagnostics.
Code
parameter_subset <- c (
"lambda_mn" ,
"lambda[1]" , "lambda[2]" , "lambda[3]" , "lambda[4]" ,
"mu[1]" , "mu[2]" , "mu[3]" , "mu[4]"
)
pnbd_short_onehierlambda2_stanfit$ draws (inc_warmup = FALSE ) |>
mcmc_trace (pars = parameter_subset) +
expand_limits (y = 0 ) +
labs (
x = "Iteration" ,
y = "Value" ,
title = "Traceplot of Sample of Lambda and Mu Values"
) +
theme (axis.text.x = element_text (size = 10 ))
We also check \(N_{eff}\) as a quick diagnostic of the fit.
Code
pnbd_short_onehierlambda2_stanfit |>
neff_ratio (pars = c ("lambda" , "mu" )) |>
mcmc_neff () +
ggtitle ("Plot of Parameter Effective Sample Sizes" )
Assess the Model
As we intend to run the same logic to assess each of our models, we have combined all this logic into a single function run_model_assessment, to run the simulations and combine the datasets.
Code
pnbd_stanfit <- pnbd_short_onehierlambda2_stanfit |>
recover_types (customer_fit_stats_tbl)
pnbd_short_onehierlambda2_assess_data_lst <- run_model_assessment (
model_stanfit = pnbd_stanfit,
insample_tbl = customer_fit_subset_tbl,
fit_label = "pnbd_short_onehierlambda2" ,
fit_end_dttm = use_fit_end_date |> as.POSIXct (),
valid_start_dttm = use_valid_start_date |> as.POSIXct (),
valid_end_dttm = use_valid_end_date |> as.POSIXct (),
sim_seed = 4210
)
pnbd_short_onehierlambda2_assess_data_lst |> glimpse ()
List of 5
$ model_fit_index_filepath : 'glue' chr "data/pnbd_short_onehierlambda2_assess_fit_index_tbl.rds"
$ model_valid_index_filepath : 'glue' chr "data/pnbd_short_onehierlambda2_assess_valid_index_tbl.rds"
$ model_simstats_filepath : 'glue' chr "data/pnbd_short_onehierlambda2_assess_model_simstats_tbl.rds"
$ model_fit_simstats_filepath : 'glue' chr "data/pnbd_short_onehierlambda2_assess_fit_simstats_tbl.rds"
$ model_valid_simstats_filepath: 'glue' chr "data/pnbd_short_onehierlambda2_assess_valid_simstats_tbl.rds"
Check In-Sample Data Validation
We first check the model against the in-sample data.
Code
simdata_tbl <- pnbd_short_onehierlambda2_assess_data_lst |>
use_series (model_fit_simstats_filepath) |>
read_rds ()
insample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_fit_subset_tbl,
simdata_tbl = simdata_tbl
)
insample_plots_lst$ multi_plot |> print ()
Code
insample_plots_lst$ total_plot |> print ()
Code
insample_plots_lst$ quant_plot |> print ()
This fit looks reasonable and appears to capture most of the aspects of the data used to fit it. Given that this is a synthetic dataset, this is not surprising, but at least we appreciate that our model is valid.
Check Out-of-Sample Data Validation
We now repeat for the out-of-sample data.
Code
simdata_tbl <- pnbd_short_onehierlambda1_assess_data_lst |>
use_series (model_valid_simstats_filepath) |>
read_rds ()
outsample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_valid_subset_tbl,
simdata_tbl = simdata_tbl
)
outsample_plots_lst$ multi_plot |> print ()
Code
outsample_plots_lst$ total_plot |> print ()
Code
outsample_plots_lst$ quant_plot |> print ()
As for our short time frame data, overall our model is working well.
Fit First Hierarchical Mu Model
We now construct the same hierarchical model but based around mu_mn.
Compile and Fit Stan Model
We compile this model using CmdStanR.
Code
pnbd_onehiermu_stanmodel <- cmdstan_model (
"stan_code/pnbd_onehier_mu.stan" ,
include_paths = stan_codedir,
pedantic = TRUE ,
dir = stan_modeldir
)
We then use this compiled model with our data to produce a fit of the data.
Code
stan_modelname <- "pnbd_short_onehiermu1"
stanfit_prefix <- str_c ("fit_" , stan_modelname)
stanfit_seed <- stanfit_seed + 1
stanfit_object_file <- glue ("data/{stanfit_prefix}_stanfit.rds" )
stan_data_lst <- customer_fit_stats_tbl |>
select (customer_id, x, t_x, T_cal) |>
compose_data (
hier_mu_mn_p1 = 0.50 ,
hier_mu_mn_p2 = 1.00 ,
lambda_mn = 0.25 ,
lambda_cv = 1.00 ,
mu_cv = 1.00
)
if (! file_exists (stanfit_object_file)) {
pnbd_short_onehiermu1_stanfit <- pnbd_onehiermu_stanmodel$ sample (
data = stan_data_lst,
chains = 4 ,
iter_warmup = 500 ,
iter_sampling = 500 ,
seed = stanfit_seed,
save_warmup = TRUE ,
output_dir = stan_modeldir,
output_basename = stanfit_prefix,
)
pnbd_short_onehiermu1_stanfit$ save_object (stanfit_object_file, compress = "gzip" )
} else {
pnbd_short_onehiermu1_stanfit <- read_rds (stanfit_object_file)
}
pnbd_short_onehiermu1_stanfit$ summary ()
# A tibble: 9,963 × 10
variable mean median sd mad q5 q95 rhat ess_bulk
<chr> <num> <num> <num> <num> <num> <num> <num> <num>
1 lp__ -4.38e+4 -4.38e+4 6.20e+1 6.43e+1 -4.39e+4 -4.37e+4 1.01 683.
2 mu_mn 1.13e-1 1.13e-1 4.47e-3 4.49e-3 1.06e-1 1.21e-1 1.01 585.
3 lambda[1] 4.45e-1 4.27e-1 1.53e-1 1.48e-1 2.28e-1 7.29e-1 1.00 2775.
4 lambda[2] 2.08e-1 1.81e-1 1.31e-1 1.16e-1 5.17e-2 4.72e-1 1.00 2112.
5 lambda[3] 2.65e-1 2.16e-1 2.04e-1 1.69e-1 3.68e-2 6.57e-1 1.00 2428.
6 lambda[4] 1.38e-1 8.69e-2 1.54e-1 9.84e-2 4.07e-3 4.37e-1 1.00 1672.
7 lambda[5] 4.94e-1 4.45e-1 2.64e-1 2.35e-1 1.60e-1 9.89e-1 1.00 1978.
8 lambda[6] 2.46e-1 1.95e-1 1.97e-1 1.48e-1 3.69e-2 6.13e-1 1.00 2000.
9 lambda[7] 1.40e-1 8.23e-2 1.62e-1 9.50e-2 4.18e-3 4.60e-1 1.00 1494.
10 lambda[8] 1.63e-1 1.54e-1 6.80e-2 6.37e-2 6.83e-2 2.85e-1 1.00 2762.
# ℹ 9,953 more rows
# ℹ 1 more variable: ess_tail <num>
We have some basic HMC-based validity statistics we can check.
Code
pnbd_short_onehiermu1_stanfit$ cmdstan_diagnose ()
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu1-1.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu1-2.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu1-3.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu1-4.csv not found
No valid input files, exiting.
Visual Diagnostics of the Sample Validity
Now that we have a sample from the posterior distribution we need to create a few different visualisations of the diagnostics.
Code
parameter_subset <- c (
"mu_mn" ,
"lambda[1]" , "lambda[2]" , "lambda[3]" , "lambda[4]" ,
"mu[1]" , "mu[2]" , "mu[3]" , "mu[4]"
)
pnbd_short_onehiermu1_stanfit$ draws (inc_warmup = FALSE ) |>
mcmc_trace (pars = parameter_subset) +
expand_limits (y = 0 ) +
labs (
x = "Iteration" ,
y = "Value" ,
title = "Traceplot of Sample of Lambda and Mu Values"
) +
theme (axis.text.x = element_text (size = 10 ))
We also check \(N_{eff}\) as a quick diagnostic of the fit.
Code
pnbd_short_onehiermu1_stanfit |>
neff_ratio (pars = c ("lambda" , "mu" )) |>
mcmc_neff () +
ggtitle ("Plot of Parameter Effective Sample Sizes" )
Assess the Model
As we intend to run the same logic to assess each of our models, we have combined all this logic into a single function run_model_assessment, to run the simulations and combine the datasets.
Code
pnbd_stanfit <- pnbd_short_onehiermu1_stanfit |>
recover_types (customer_fit_stats_tbl)
pnbd_short_onehiermu1_assess_data_lst <- run_model_assessment (
model_stanfit = pnbd_stanfit,
insample_tbl = customer_fit_subset_tbl,
fit_label = "pnbd_short_onehiermu1" ,
fit_end_dttm = use_fit_end_date |> as.POSIXct (),
valid_start_dttm = use_valid_start_date |> as.POSIXct (),
valid_end_dttm = use_valid_end_date |> as.POSIXct (),
sim_seed = 4210
)
pnbd_short_onehiermu1_assess_data_lst |> glimpse ()
List of 5
$ model_fit_index_filepath : 'glue' chr "data/pnbd_short_onehiermu1_assess_fit_index_tbl.rds"
$ model_valid_index_filepath : 'glue' chr "data/pnbd_short_onehiermu1_assess_valid_index_tbl.rds"
$ model_simstats_filepath : 'glue' chr "data/pnbd_short_onehiermu1_assess_model_simstats_tbl.rds"
$ model_fit_simstats_filepath : 'glue' chr "data/pnbd_short_onehiermu1_assess_fit_simstats_tbl.rds"
$ model_valid_simstats_filepath: 'glue' chr "data/pnbd_short_onehiermu1_assess_valid_simstats_tbl.rds"
Check In-Sample Data Validation
We first check the model against the in-sample data.
Code
simdata_tbl <- pnbd_short_onehiermu1_assess_data_lst |>
use_series (model_fit_simstats_filepath) |>
read_rds ()
insample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_fit_subset_tbl,
simdata_tbl = simdata_tbl
)
insample_plots_lst$ multi_plot |> print ()
Code
insample_plots_lst$ total_plot |> print ()
Code
insample_plots_lst$ quant_plot |> print ()
This fit looks reasonable and appears to capture most of the aspects of the data used to fit it. Given that this is a synthetic dataset, this is not surprising, but at least we appreciate that our model is valid.
Check Out-of-Sample Data Validation
We now repeat for the out-of-sample data.
Code
simdata_tbl <- pnbd_short_onehierlambda1_assess_data_lst |>
use_series (model_valid_simstats_filepath) |>
read_rds ()
outsample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_valid_subset_tbl,
simdata_tbl = simdata_tbl
)
outsample_plots_lst$ multi_plot |> print ()
Code
outsample_plots_lst$ total_plot |> print ()
Code
outsample_plots_lst$ quant_plot |> print ()
As for our short time frame data, overall our model is working well.
Fit Second Hierarchical Mu Model
In this model, we are going with a broadly similar model but we are instead using a different mean for our hierarchical prior.
Fit Stan Model
We now want to fit the model to our data using this alternative prior for lambda_mn.
Code
stan_modelname <- "pnbd_short_onehiermu2"
stanfit_prefix <- str_c ("fit_" , stan_modelname)
stanfit_seed <- stanfit_seed + 1
stanfit_object_file <- glue ("data/{stanfit_prefix}_stanfit.rds" )
stan_data_lst <- customer_fit_stats_tbl |>
select (customer_id, x, t_x, T_cal) |>
compose_data (
hier_mu_mn_p1 = 0.25 ,
hier_mu_mn_p2 = 1.00 ,
lambda_mn = 0.25 ,
lambda_cv = 1.00 ,
mu_cv = 1.00
)
if (! file_exists (stanfit_object_file)) {
pnbd_short_onehiermu2_stanfit <- pnbd_onehiermu_stanmodel$ sample (
data = stan_data_lst,
chains = 4 ,
iter_warmup = 500 ,
iter_sampling = 500 ,
seed = stanfit_seed,
save_warmup = TRUE ,
output_dir = stan_modeldir,
output_basename = stanfit_prefix,
)
pnbd_short_onehiermu2_stanfit$ save_object (stanfit_object_file, compress = "gzip" )
} else {
pnbd_short_onehiermu2_stanfit <- read_rds (stanfit_object_file)
}
pnbd_short_onehiermu2_stanfit$ summary ()
# A tibble: 9,963 × 10
variable mean median sd mad q5 q95 rhat ess_bulk
<chr> <num> <num> <num> <num> <num> <num> <num> <num>
1 lp__ -4.38e+4 -4.38e+4 6.49e+1 6.69e+1 -4.39e+4 -4.37e+4 1.01 593.
2 mu_mn 1.13e-1 1.13e-1 4.39e-3 4.38e-3 1.06e-1 1.20e-1 1.01 384.
3 lambda[1] 4.47e-1 4.27e-1 1.54e-1 1.48e-1 2.27e-1 7.37e-1 1.00 3278.
4 lambda[2] 2.11e-1 1.80e-1 1.31e-1 1.16e-1 5.67e-2 4.55e-1 1.01 2523.
5 lambda[3] 2.63e-1 2.06e-1 2.09e-1 1.69e-1 4.08e-2 6.84e-1 1.00 1921.
6 lambda[4] 1.45e-1 8.38e-2 1.69e-1 9.54e-2 5.07e-3 4.89e-1 1.00 1713.
7 lambda[5] 4.91e-1 4.43e-1 2.73e-1 2.55e-1 1.53e-1 1.00e+0 1.00 2035.
8 lambda[6] 2.44e-1 2.01e-1 1.99e-1 1.55e-1 3.46e-2 6.19e-1 1.01 2510.
9 lambda[7] 1.37e-1 8.37e-2 1.53e-1 9.09e-2 5.49e-3 4.47e-1 1.00 1927.
10 lambda[8] 1.64e-1 1.56e-1 6.82e-2 6.40e-2 6.82e-2 2.88e-1 1.00 3151.
# ℹ 9,953 more rows
# ℹ 1 more variable: ess_tail <num>
We have some basic HMC-based validity statistics we can check.
Code
pnbd_short_onehiermu2_stanfit$ cmdstan_diagnose ()
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu2-1.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu2-2.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu2-3.csv not found
File /home/rstudio/btydwork/stan_models/fit_pnbd_init_short_onehiermu2-4.csv not found
No valid input files, exiting.
Visual Diagnostics of the Sample Validity
Now that we have a sample from the posterior distribution we need to create a few different visualisations of the diagnostics.
Code
parameter_subset <- c (
"mu_mn" ,
"lambda[1]" , "lambda[2]" , "lambda[3]" , "lambda[4]" ,
"mu[1]" , "mu[2]" , "mu[3]" , "mu[4]"
)
pnbd_short_onehiermu2_stanfit$ draws (inc_warmup = FALSE ) |>
mcmc_trace (pars = parameter_subset) +
expand_limits (y = 0 ) +
labs (
x = "Iteration" ,
y = "Value" ,
title = "Traceplot of Sample of Lambda and Mu Values"
) +
theme (axis.text.x = element_text (size = 10 ))
We also check \(N_{eff}\) as a quick diagnostic of the fit.
Code
pnbd_short_onehiermu2_stanfit |>
neff_ratio (pars = c ("lambda" , "mu" )) |>
mcmc_neff () +
ggtitle ("Plot of Parameter Effective Sample Sizes" )
Assess the Model
As we intend to run the same logic to assess each of our models, we have combined all this logic into a single function run_model_assessment, to run the simulations and combine the datasets.
Code
pnbd_stanfit <- pnbd_short_onehiermu2_stanfit |>
recover_types (customer_fit_stats_tbl)
pnbd_short_onehiermu2_assess_data_lst <- run_model_assessment (
model_stanfit = pnbd_stanfit,
insample_tbl = customer_fit_subset_tbl,
fit_label = "pnbd_short_onehiermu2" ,
fit_end_dttm = use_fit_end_date |> as.POSIXct (),
valid_start_dttm = use_valid_start_date |> as.POSIXct (),
valid_end_dttm = use_valid_end_date |> as.POSIXct (),
sim_seed = 4210
)
pnbd_short_onehiermu2_assess_data_lst |> glimpse ()
List of 5
$ model_fit_index_filepath : 'glue' chr "data/pnbd_short_onehiermu2_assess_fit_index_tbl.rds"
$ model_valid_index_filepath : 'glue' chr "data/pnbd_short_onehiermu2_assess_valid_index_tbl.rds"
$ model_simstats_filepath : 'glue' chr "data/pnbd_short_onehiermu2_assess_model_simstats_tbl.rds"
$ model_fit_simstats_filepath : 'glue' chr "data/pnbd_short_onehiermu2_assess_fit_simstats_tbl.rds"
$ model_valid_simstats_filepath: 'glue' chr "data/pnbd_short_onehiermu2_assess_valid_simstats_tbl.rds"
Check In-Sample Data Validation
We first check the model against the in-sample data.
Code
simdata_tbl <- pnbd_short_onehiermu2_assess_data_lst |>
use_series (model_fit_simstats_filepath) |>
read_rds ()
insample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_fit_subset_tbl,
simdata_tbl = simdata_tbl
)
insample_plots_lst$ multi_plot |> print ()
Code
insample_plots_lst$ total_plot |> print ()
Code
insample_plots_lst$ quant_plot |> print ()
This fit looks reasonable and appears to capture most of the aspects of the data used to fit it. Given that this is a synthetic dataset, this is not surprising, but at least we appreciate that our model is valid.
Check Out-of-Sample Data Validation
We now repeat for the out-of-sample data.
Code
simdata_tbl <- pnbd_short_onehiermu1_assess_data_lst |>
use_series (model_valid_simstats_filepath) |>
read_rds ()
outsample_plots_lst <- create_model_assessment_plots (
obsdata_tbl = customer_valid_subset_tbl,
simdata_tbl = simdata_tbl
)
outsample_plots_lst$ multi_plot |> print ()
Code
outsample_plots_lst$ total_plot |> print ()
Code
outsample_plots_lst$ quant_plot |> print ()
As for our short time frame data, overall our model is working well.
Compare Model Outputs
We have looked at each of the models individually, but it is also worth looking at each of the models as a group.
Code
calculate_simulation_statistics <- function (file_rds) {
simdata_tbl <- read_rds (file_rds)
multicount_cust_tbl <- simdata_tbl |>
filter (sim_tnx_count > 0 ) |>
count (draw_id, name = "multicust_count" )
totaltnx_data_tbl <- simdata_tbl |>
count (draw_id, wt = sim_tnx_count, name = "simtnx_count" )
simstats_tbl <- multicount_cust_tbl |>
inner_join (totaltnx_data_tbl, by = "draw_id" )
return (simstats_tbl)
}
Code
obs_fit_customer_count <- customer_fit_subset_tbl |>
filter (tnx_count > 0 ) |>
nrow ()
obs_valid_customer_count <- customer_valid_subset_tbl |>
filter (tnx_count > 0 ) |>
nrow ()
obs_fit_total_count <- customer_fit_subset_tbl |>
pull (tnx_count) |>
sum ()
obs_valid_total_count <- customer_valid_subset_tbl |>
pull (tnx_count) |>
sum ()
obs_stats_tbl <- tribble (
~ assess_type, ~ name, ~ obs_value,
"fit" , "multicust_count" , obs_fit_customer_count,
"fit" , "simtnx_count" , obs_fit_total_count,
"valid" , "multicust_count" , obs_valid_customer_count,
"valid" , "simtnx_count" , obs_valid_total_count
)
model_assess_tbl <- dir_ls ("data" , regexp = "pnbd_short_(one|fixed).*_assess_.*simstats" ) |>
enframe (name = NULL , value = "file_path" ) |>
filter (str_detect (file_path, "_assess_model_" , negate = TRUE )) |>
mutate (
model_label = str_replace (file_path, "data/pnbd_short_(.*?)_assess_.*" , " \\ 1" ),
assess_type = if_else (str_detect (file_path, "_assess_fit_" ), "fit" , "valid" ),
sim_data = map (
file_path, calculate_simulation_statistics,
.progress = "calculate_simulation_statistics"
)
)
model_assess_tbl |> glimpse ()
Rows: 16
Columns: 4
$ file_path <fs::path> "data/pnbd_short_fixed1_assess_fit_simstats_tbl.rds",…
$ model_label <chr> "fixed1", "fixed1", "fixed2", "fixed2", "fixed3", "fixed3"…
$ assess_type <chr> "fit", "valid", "fit", "valid", "fit", "valid", "fit", "va…
$ sim_data <list> [<tbl_df[2000 x 3]>], [<tbl_df[2000 x 3]>], [<tbl_df[2000…
Code
model_assess_summstat_tbl <- model_assess_tbl |>
select (model_label, assess_type, sim_data) |>
unnest (sim_data) |>
pivot_longer (
cols = ! c (model_label, assess_type, draw_id)
) |>
group_by (model_label, assess_type, name) |>
summarise (
.groups = "drop" ,
mean_val = mean (value),
p10 = quantile (value, 0.10 ),
p25 = quantile (value, 0.25 ),
p50 = quantile (value, 0.50 ),
p75 = quantile (value, 0.75 ),
p90 = quantile (value, 0.90 )
)
model_assess_summstat_tbl |> glimpse ()
Rows: 32
Columns: 9
$ model_label <chr> "fixed1", "fixed1", "fixed1", "fixed1", "fixed2", "fixed2"…
$ assess_type <chr> "fit", "fit", "valid", "valid", "fit", "fit", "valid", "va…
$ name <chr> "multicust_count", "simtnx_count", "multicust_count", "sim…
$ mean_val <dbl> 601.6880, 4081.1590, 158.9110, 1559.5810, 671.4355, 3094.8…
$ p10 <dbl> 583.0, 3819.0, 149.0, 1399.0, 653.0, 2907.9, 110.9, 686.0,…
$ p25 <dbl> 592.00, 3936.00, 153.00, 1470.00, 662.00, 2996.00, 115.00,…
$ p50 <dbl> 602.0, 4079.0, 159.0, 1553.0, 672.0, 3095.0, 119.0, 787.0,…
$ p75 <dbl> 612.00, 4220.00, 165.00, 1647.00, 681.00, 3194.00, 124.00,…
$ p90 <dbl> 620.0, 4357.0, 169.0, 1733.1, 689.0, 3282.0, 128.0, 897.0,…
Code
#! echo: TRUE
ggplot (model_assess_summstat_tbl) +
geom_errorbar (
aes (x = model_label, ymin = p10, ymax = p90), width = 0
) +
geom_errorbar (
aes (x = model_label, ymin = p25, ymax = p75), width = 0 , linewidth = 3
) +
geom_hline (
aes (yintercept = obs_value),
data = obs_stats_tbl, colour = "red"
) +
scale_y_continuous (labels = label_comma ()) +
expand_limits (y = 0 ) +
facet_wrap (
vars (assess_type, name), scale = "free_y"
) +
labs (
x = "Model" ,
y = "Count" ,
title = "Comparison Plot for the Different Models"
) +
theme (
axis.text.x = element_text (angle = 20 , vjust = 0.5 , size = 8 )
)
Write Assessment Data to Disk
We now want to save the assessment data to disk.
Code
model_assess_tbl |> write_rds ("data/assess_data_pnbd_short_onehier_tbl.rds" )
R Environment
Code
options (width = 120L)
sessioninfo:: session_info ()
─ Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────
setting value
version R version 4.3.1 (2023-06-16)
os Ubuntu 22.04.3 LTS
system x86_64, linux-gnu
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz Europe/Dublin
date 2023-11-11
pandoc 3.1.1 @ /usr/local/bin/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
abind 1.4-5 2016-07-21 [1] RSPM (R 4.3.0)
arrayhelpers 1.1-0 2020-02-04 [1] RSPM (R 4.3.0)
backports 1.4.1 2021-12-13 [1] RSPM (R 4.3.0)
base64enc 0.1-3 2015-07-28 [1] RSPM (R 4.3.0)
bayesplot * 1.10.0 2022-11-16 [1] RSPM (R 4.3.0)
bit 4.0.5 2022-11-15 [1] RSPM (R 4.3.0)
bit64 4.0.5 2020-08-30 [1] RSPM (R 4.3.0)
bridgesampling 1.1-2 2021-04-16 [1] RSPM (R 4.3.0)
brms * 2.20.4 2023-09-25 [1] RSPM (R 4.3.0)
Brobdingnag 1.2-9 2022-10-19 [1] RSPM (R 4.3.0)
cachem 1.0.8 2023-05-01 [1] RSPM (R 4.3.0)
callr 3.7.3 2022-11-02 [1] RSPM (R 4.3.0)
checkmate 2.3.0 2023-10-25 [1] RSPM (R 4.3.0)
cli 3.6.1 2023-03-23 [1] RSPM (R 4.3.0)
cmdstanr * 0.6.0.9000 2023-11-07 [1] Github (stan-dev/cmdstanr@a13c798)
coda 0.19-4 2020-09-30 [1] RSPM (R 4.3.0)
codetools 0.2-19 2023-02-01 [2] CRAN (R 4.3.1)
colorspace 2.1-0 2023-01-23 [1] RSPM (R 4.3.0)
colourpicker 1.3.0 2023-08-21 [1] RSPM (R 4.3.0)
conflicted * 1.2.0 2023-02-01 [1] RSPM (R 4.3.0)
cowplot * 1.1.1 2020-12-30 [1] RSPM (R 4.3.0)
crayon 1.5.2 2022-09-29 [1] RSPM (R 4.3.0)
crosstalk 1.2.0 2021-11-04 [1] RSPM (R 4.3.0)
curl 5.1.0 2023-10-02 [1] RSPM (R 4.3.0)
digest 0.6.33 2023-07-07 [1] RSPM (R 4.3.0)
directlabels * 2023.8.25 2023-09-01 [1] RSPM (R 4.3.0)
distributional 0.3.2 2023-03-22 [1] RSPM (R 4.3.0)
dplyr * 1.1.3 2023-09-03 [1] RSPM (R 4.3.0)
DT 0.30 2023-10-05 [1] RSPM (R 4.3.0)
dygraphs 1.1.1.6 2018-07-11 [1] RSPM (R 4.3.0)
ellipsis 0.3.2 2021-04-29 [1] RSPM (R 4.3.0)
evaluate 0.22 2023-09-29 [1] RSPM (R 4.3.0)
fansi 1.0.5 2023-10-08 [1] RSPM (R 4.3.0)
farver 2.1.1 2022-07-06 [1] RSPM (R 4.3.0)
fastmap 1.1.1 2023-02-24 [1] RSPM (R 4.3.0)
forcats * 1.0.0 2023-01-29 [1] RSPM (R 4.3.0)
fs * 1.6.3 2023-07-20 [1] RSPM (R 4.3.0)
furrr * 0.3.1 2022-08-15 [1] RSPM (R 4.3.0)
future * 1.33.0 2023-07-01 [1] RSPM (R 4.3.0)
generics 0.1.3 2022-07-05 [1] RSPM (R 4.3.0)
ggdist 3.3.0 2023-05-13 [1] RSPM (R 4.3.0)
ggplot2 * 3.4.4 2023-10-12 [1] RSPM (R 4.3.0)
globals 0.16.2 2022-11-21 [1] RSPM (R 4.3.0)
glue * 1.6.2 2022-02-24 [1] RSPM (R 4.3.0)
gridExtra 2.3 2017-09-09 [1] RSPM (R 4.3.0)
gtable 0.3.4 2023-08-21 [1] RSPM (R 4.3.0)
gtools 3.9.4 2022-11-27 [1] RSPM (R 4.3.0)
hms 1.1.3 2023-03-21 [1] RSPM (R 4.3.0)
htmltools 0.5.6.1 2023-10-06 [1] RSPM (R 4.3.0)
htmlwidgets 1.6.2 2023-03-17 [1] RSPM (R 4.3.0)
httpuv 1.6.12 2023-10-23 [1] RSPM (R 4.3.0)
igraph 1.5.1 2023-08-10 [1] RSPM (R 4.3.0)
inline 0.3.19 2021-05-31 [1] RSPM (R 4.3.0)
jsonlite 1.8.7 2023-06-29 [1] RSPM (R 4.3.0)
knitr 1.44 2023-09-11 [1] RSPM (R 4.3.0)
labeling 0.4.3 2023-08-29 [1] RSPM (R 4.3.0)
later 1.3.1 2023-05-02 [1] RSPM (R 4.3.0)
lattice 0.21-8 2023-04-05 [2] CRAN (R 4.3.1)
lifecycle 1.0.3 2022-10-07 [1] RSPM (R 4.3.0)
listenv 0.9.0 2022-12-16 [1] RSPM (R 4.3.0)
loo 2.6.0 2023-03-31 [1] RSPM (R 4.3.0)
lubridate * 1.9.3 2023-09-27 [1] RSPM (R 4.3.0)
magrittr * 2.0.3 2022-03-30 [1] RSPM (R 4.3.0)
markdown 1.11 2023-10-19 [1] RSPM (R 4.3.0)
Matrix 1.5-4.1 2023-05-18 [2] CRAN (R 4.3.1)
matrixStats 1.0.0 2023-06-02 [1] RSPM (R 4.3.0)
memoise 2.0.1 2021-11-26 [1] RSPM (R 4.3.0)
mime 0.12 2021-09-28 [1] RSPM (R 4.3.0)
miniUI 0.1.1.1 2018-05-18 [1] RSPM (R 4.3.0)
munsell 0.5.0 2018-06-12 [1] RSPM (R 4.3.0)
mvtnorm 1.2-3 2023-08-25 [1] RSPM (R 4.3.0)
nlme 3.1-162 2023-01-31 [2] CRAN (R 4.3.1)
parallelly 1.36.0 2023-05-26 [1] RSPM (R 4.3.0)
pillar 1.9.0 2023-03-22 [1] RSPM (R 4.3.0)
pkgbuild 1.4.2 2023-06-26 [1] RSPM (R 4.3.0)
pkgconfig 2.0.3 2019-09-22 [1] RSPM (R 4.3.0)
plyr 1.8.9 2023-10-02 [1] RSPM (R 4.3.0)
posterior * 1.4.1 2023-03-14 [1] RSPM (R 4.3.0)
prettyunits 1.2.0 2023-09-24 [1] RSPM (R 4.3.0)
processx 3.8.2 2023-06-30 [1] RSPM (R 4.3.0)
promises 1.2.1 2023-08-10 [1] RSPM (R 4.3.0)
ps 1.7.5 2023-04-18 [1] RSPM (R 4.3.0)
purrr * 1.0.2 2023-08-10 [1] RSPM (R 4.3.0)
quadprog 1.5-8 2019-11-20 [1] RSPM (R 4.3.0)
QuickJSR 1.0.7 2023-10-15 [1] RSPM (R 4.3.0)
R6 2.5.1 2021-08-19 [1] RSPM (R 4.3.0)
Rcpp * 1.0.11 2023-07-06 [1] RSPM (R 4.3.0)
RcppParallel 5.1.7 2023-02-27 [1] RSPM (R 4.3.0)
readr * 2.1.4 2023-02-10 [1] RSPM (R 4.3.0)
reshape2 1.4.4 2020-04-09 [1] RSPM (R 4.3.0)
rlang * 1.1.1 2023-04-28 [1] RSPM (R 4.3.0)
rmarkdown 2.25 2023-09-18 [1] RSPM (R 4.3.0)
rstan 2.32.3 2023-10-15 [1] RSPM (R 4.3.0)
rstantools 2.3.1.1 2023-07-18 [1] RSPM (R 4.3.0)
rstudioapi 0.15.0 2023-07-07 [1] RSPM (R 4.3.0)
rsyslog * 1.0.3 2023-05-08 [1] RSPM (R 4.3.0)
scales * 1.2.1 2022-08-20 [1] RSPM (R 4.3.0)
sessioninfo 1.2.2 2021-12-06 [1] RSPM (R 4.3.0)
shiny 1.7.5.1 2023-10-14 [1] RSPM (R 4.3.0)
shinyjs 2.1.0 2021-12-23 [1] RSPM (R 4.3.0)
shinystan 2.6.0 2022-03-03 [1] RSPM (R 4.3.0)
shinythemes 1.2.0 2021-01-25 [1] RSPM (R 4.3.0)
StanHeaders 2.26.28 2023-09-07 [1] RSPM (R 4.3.0)
stringi 1.7.12 2023-01-11 [1] RSPM (R 4.3.0)
stringr * 1.5.0 2022-12-02 [1] RSPM (R 4.3.0)
svUnit 1.0.6 2021-04-19 [1] RSPM (R 4.3.0)
tensorA 0.36.2 2020-11-19 [1] RSPM (R 4.3.0)
threejs 0.3.3 2020-01-21 [1] RSPM (R 4.3.0)
tibble * 3.2.1 2023-03-20 [1] RSPM (R 4.3.0)
tidybayes * 3.0.6 2023-08-12 [1] RSPM (R 4.3.0)
tidyr * 1.3.0 2023-01-24 [1] RSPM (R 4.3.0)
tidyselect 1.2.0 2022-10-10 [1] RSPM (R 4.3.0)
tidyverse * 2.0.0 2023-02-22 [1] RSPM (R 4.3.0)
timechange 0.2.0 2023-01-11 [1] RSPM (R 4.3.0)
tzdb 0.4.0 2023-05-12 [1] RSPM (R 4.3.0)
utf8 1.2.4 2023-10-22 [1] RSPM (R 4.3.0)
V8 4.4.0 2023-10-09 [1] RSPM (R 4.3.0)
vctrs 0.6.4 2023-10-12 [1] RSPM (R 4.3.0)
vroom 1.6.4 2023-10-02 [1] RSPM (R 4.3.0)
withr 2.5.1 2023-09-26 [1] RSPM (R 4.3.0)
xfun 0.40 2023-08-09 [1] RSPM (R 4.3.0)
xtable 1.8-4 2019-04-21 [1] RSPM (R 4.3.0)
xts 0.13.1 2023-04-16 [1] RSPM (R 4.3.0)
yaml 2.3.7 2023-01-23 [1] RSPM (R 4.3.0)
zoo 1.8-12 2023-04-13 [1] RSPM (R 4.3.0)
[1] /usr/local/lib/R/site-library
[2] /usr/local/lib/R/library
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Code